﻿/* MainPage.xaml.cs ---------------------------------------------------------
 *
 * Informatix Football Apps
 * QB Passing Efficiency Calculator (Silverlight App)
 *
 * © 2013 Jason Barkes - http://jbarkes.blogspot.com
 ----------------------------------------------------------------------------*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace QBRatingSL
{
    public partial class MainPage : UserControl
    {
        // QB passing stats and calculated stats
        double _comps, _atts, _yards, _tds, _ints;
        double _cp, _ya, _tp, _ip;

        // Key code constants
        const int KEY_DECIMAL_POINT = 110;
        const int KEY_DASH          = 189;
        const int KEY_PERIOD        = 190;

        const double NFL_MAX        = 2.375;

        public MainPage()
        {
            InitializeComponent();
        }

        #region ~~ Numeric Fields Only Event Handlers ~~
        private void ctlCompletions_KeyDown(object sender, KeyEventArgs e)
        {
            AcceptNumericOnly(sender, e);
        }

        private void ctlAttempts_KeyDown(object sender, KeyEventArgs e)
        {
            AcceptNumericOnly(sender, e);
        }

        private void ctlYards_KeyDown(object sender, KeyEventArgs e)
        {
            AcceptNumericOnly(sender, e);
        }

        private void ctlTds_KeyDown(object sender, KeyEventArgs e)
        {
            AcceptNumericOnly(sender, e);
        }

        private void ctlInts_KeyDown(object sender, KeyEventArgs e)
        {
            AcceptNumericOnly(sender, e);
        }
        #endregion // ~~ Numeric Fields Only ~~

        #region ~~ Read Only Fields Event Handlers ~~
        private void ctlCp_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlCpCalc_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlCpAct_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlYa_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlYaCalc_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlYaAct_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlTp_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlTpCalc_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlTpAct_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlIp_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlIpCalc_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlIpAct_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlCpFinal_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlYaFinal_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlTpFinal_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlIpFinal_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlRawFinal_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlCpNcaa_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlYaNcaa_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlYaActNcaa_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlTpNcaa_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlTpActNcaa_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlIpNcaa_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlIpActNcaa_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlCpNcaaFinal_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlYaNcaaFinal_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlTpNcaaFinal_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void ctlIpNcaaFinal_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }
        #endregion

        /// <summary>
        /// Event handler that clears the text from all the textboxes
        /// </summary>
        private void btnReset_Click(object sender, RoutedEventArgs e)
        {
            List<TextBox> txtCtlsList = new List<TextBox>();
            FindTextElements(this.LayoutRoot, txtCtlsList);

            // Clear the non-empty textboxes
            var filteredTxtCtlsList = txtCtlsList.Where(ctl => ctl.Text != string.Empty).ToList();
            filteredTxtCtlsList.ForEach(ctl => ctl.Text = string.Empty);
        }

        /// <summary>
        /// Event handler that performs the actual QB rating calculations
        /// </summary>
        private void btnCalc_Click(object sender, RoutedEventArgs e)
        {
            if (VerifyStats())
            {
                CalculateRatings();
            }
        }

        /// <summary>
        /// Method to accept only numeric (and numerically useful) key codes
        /// </summary>
        private static void AcceptNumericOnly(object sender, KeyEventArgs e)
        {
            e.Handled = !(
                (!((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift
                || (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control
                || (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt)
                && ((e.Key >= Key.D0 && e.Key <= Key.D9) || (e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9)
                   ||  e.Key == Key.Subtract || e.Key == Key.Add || e.Key == Key.Decimal
                   ||  e.Key == Key.Home || e.Key == Key.End || e.Key == Key.Delete ||  e.Key == Key.Tab
                   ||  e.Key == Key.Enter || e.Key == Key.Escape || e.Key == Key.Back
                   || (e.Key == Key.Unknown
                      && (e.PlatformKeyCode == KEY_DECIMAL_POINT
                      ||  e.PlatformKeyCode == KEY_DASH
                      ||  e.PlatformKeyCode == KEY_PERIOD)))
                )
            );
        }

        /// <summary>
        /// Method to recursively retrieve a list of all textbox controls
        /// </summary>
        private void FindTextElements(UIElement rootElement, List<TextBox> txtCtlsList)
        {
            TextBox textBox = rootElement as TextBox;
            if (textBox != null)
            {
                // If the element is a textbox then add it to the list
                txtCtlsList.Add(textBox);
            }
            else
            {
                Panel panel = rootElement as Panel;
                if (panel != null)
                {
                    // Iterate any children
                    foreach (UIElement child in panel.Children)
                    {
                        FindTextElements(child, txtCtlsList);
                    }
                }
            }
        }

        /// <summary>
        /// Calculate the NFL and NCAA QB ratings
        /// </summary>
        private void CalculateRatings()
        {
            _comps = Convert.ToDouble(ctlCompletions.Text); // Completions
            _atts  = Convert.ToDouble(ctlAttempts.Text);    // Passing attempts
            _yards = Convert.ToDouble(ctlYards.Text);       // Passing yards
            _tds   = Convert.ToDouble(ctlTds.Text);         // Passing TDs
            _ints  = Convert.ToDouble(ctlInts.Text);        // Interceptions

            _cp    = (_comps / _atts) * 100;                // Completion percentage
            _ya    = (_yards / _atts);                      // Yards per attempt
            _tp    = (_tds / _atts) * 100;                  // Touchdown percentage
            _ip    = (_ints / _atts) * 100;                 // Interception percentage

            double nflCpCalc = 0.0, nflYaCalc = 0.0, nflTpCalc = 0.0, nflIpCalc = 0.0,
                   nflCpAct = 0.0, nflYaAct = 0.0, nflTpAct = 0.0, nflIpAct = 0.0,
                   ncaaYaCalc = 0.0, ncaaTpCalc = 0.0, ncaaIpCalc = 0.0;

            double nflRawRating = 0.0, nflRating = 0.0, ncaaRating = 0.0;

            // Completion Percentage (adjusted NFL value must be between 0 and 2.375)
            nflCpCalc = nflCpAct = (_cp - 30) * 0.05;

            if (nflCpCalc < 0)
            {
                nflCpAct = 0;
            }
            else if (nflCpCalc > NFL_MAX)
            {
                nflCpAct = NFL_MAX;
            }

            ctlCp.Text = _cp.ToString("f2");
            ctlCpCalc.Text = nflCpCalc.ToString("f3");
            ctlCpAct.Text = nflCpAct.ToString("f3");
            ctlCpFinal.Text = nflCpAct.ToString("f3");
            ctlCpNcaa.Text = _cp.ToString("f2");
            ctlCpNcaaFinal.Text = _cp.ToString("f2");

            // Yards per Attempt (adjusted NFL value must be between 0 and 2.375)
            nflYaAct = nflYaCalc = (_ya - 3) * 0.25;

            if (nflYaCalc < 0)
            {
                nflYaAct = 0;
            }
            else if (nflYaCalc > NFL_MAX)
            {
                nflYaAct = NFL_MAX;
            }

            ncaaYaCalc = _ya * 8.4;

            ctlYa.Text = _ya.ToString("f2");
            ctlYaCalc.Text = nflYaCalc.ToString("f3");
            ctlYaAct.Text = nflYaAct.ToString("f3");
            ctlYaFinal.Text = nflYaAct.ToString("f3");
            ctlYaNcaa.Text = _ya.ToString("f2");
            ctlYaActNcaa.Text = ncaaYaCalc.ToString("f2");
            ctlYaNcaaFinal.Text = ncaaYaCalc.ToString("f2");

            // TD Percentage (adjusted NFL value must be < 2.375)
            nflTpAct = nflTpCalc = (_tp * 0.2);

            if (nflTpCalc > NFL_MAX)
            {
                nflTpAct = NFL_MAX;
            }

            ncaaTpCalc = _tp * 3.3;

            ctlTp.Text = _tp.ToString("f2");
            ctlTpCalc.Text = nflTpCalc.ToString("f3");
            ctlTpAct.Text = nflTpAct.ToString("f3");
            ctlTpFinal.Text = nflTpAct.ToString("f3");
            ctlTpNcaa.Text = _tp.ToString("f2");
            ctlTpActNcaa.Text = ncaaTpCalc.ToString("f2");
            ctlTpNcaaFinal.Text = ncaaTpCalc.ToString("f2");

            // Interception Percentage (adjusted NFL value must be > 0)
            nflIpAct = nflIpCalc = NFL_MAX - (_ip * 0.25);

            if (nflIpCalc < 0)
            {
                nflIpAct = 0;
            }

            ncaaIpCalc = _ip * 2;

            ctlIp.Text = _ip.ToString("f2");
            ctlIpCalc.Text = nflIpCalc.ToString("f3");
            ctlIpAct.Text = nflIpAct.ToString("f3");
            ctlIpFinal.Text = nflIpAct.ToString("f3");
            ctlIpNcaa.Text = _ip.ToString("f2");
            ctlIpActNcaa.Text = ncaaIpCalc.ToString("f2");
            ctlIpNcaaFinal.Text = ncaaIpCalc.ToString("f2");

            // Final calculations
            nflRawRating = (nflCpAct + nflYaAct + nflTpAct + nflIpAct) / 6;
            ctlRawFinal.Text = nflRawRating.ToString("f3");
            nflRating = nflRawRating * 100;
            ctlNflFinal.Text = nflRating.ToString("f1");
            ctlNflRating.Text = nflRating.ToString("f1");

            ncaaRating = _cp + ncaaYaCalc + ncaaTpCalc - ncaaIpCalc;
            ctlNcaaFinal.Text = ncaaRating.ToString("f1");
            ctlNcaaRating.Text = ncaaRating.ToString("f1");
        }
        
        /// <summary>
        /// This method verifies the passing stats entered by the user
        /// </summary>
        private bool VerifyStats()
        {
            if (string.IsNullOrWhiteSpace(ctlCompletions.Text))
            {
                MessageBox.Show("Please specify the number of passing completions.");
                ctlCompletions.Focus();
                return false;
            }

            if (string.IsNullOrWhiteSpace(ctlAttempts.Text))
            {
                MessageBox.Show("Please specify the number of passing attempts.");
                ctlAttempts.Focus();
                return false;
            }

            if (string.IsNullOrWhiteSpace(ctlYards.Text))
            {
                MessageBox.Show("Please specify the number of passing yards.");
                ctlYards.Focus();
                return false;
            }

            if (string.IsNullOrWhiteSpace(ctlTds.Text))
            {
                MessageBox.Show("Please specify the number of passing TDs.");
                ctlTds.Focus();
                return false;
            }

            if (string.IsNullOrWhiteSpace(ctlInts.Text))
            {
                MessageBox.Show("Please specify the number of interceptions.");
                ctlInts.Focus();
                return false;
            }

            try
            {
                int comps = Convert.ToInt32(ctlCompletions.Text);
                int atts = Convert.ToInt32(ctlAttempts.Text);
                int tds = Convert.ToInt32(ctlTds.Text);
                int ints = Convert.ToInt32(ctlInts.Text);

                if (comps < 0)
                {
                    MessageBox.Show("Completions must be a positive number.");
                    ctlCompletions.Focus();
                    return false;
                }

                if (atts < 0)
                {
                    MessageBox.Show("Attempts must be a positive number.");
                    ctlAttempts.Focus();
                    return false;
                }

                if (tds < 0)
                {
                    MessageBox.Show("Passing TDs must be a positive number.");
                    ctlTds.Focus();
                    return false;
                }

                if (ints < 0)
                {
                    MessageBox.Show("Interceptions must be a positive number.");
                    ctlInts.Focus();
                    return false;
                }

                if (atts < comps)
                {
                    MessageBox.Show("Attempts must be greater than or equal to the number of completions.");
                    ctlAttempts.Focus();
                    return false;
                }

                if (atts < (comps + ints))
                {
                    MessageBox.Show("Attempts must be greater than or equal to the total number of completions and interceptions.");
                    ctlAttempts.Focus();
                    return false;
                }

                if (comps < tds)
                {
                    MessageBox.Show("Completions must be greater than or equal to the number of passing TDs.");
                    ctlCompletions.Focus();
                    return false;
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + "\n" + ex.StackTrace);
            }

            return true;
        }

    }
}
